//
// Created by denglibin on 2021/9/10.
//

#include "05_buffer_event.h"
#include "init.h"
#include "log.h"
#include <stdlib.h>
#include <event2/listener.h>
#include <event2/bufferevent.h>
#ifndef _WIN32
#include <fcntl.h>
#include <sys/types.h>
#include<unistd.h>
#include <sys/stat.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#endif
/**
 * 写回调
 * @param be
 * @param arg
 */
static void write_cb(struct bufferevent* be, void* arg);
/**
 * 读回调
 * @param be
 * @param arg
 */
static void read_cb(struct bufferevent* be, void* arg);

/**
 * 事件(错误，超时，断开)回调
 * @param be
 * @param arg
 */
static void event_cb(struct bufferevent* be, short  what, void* arg);
/**
 * 端口新的连接回调
 * @param evconnlistener
 * @param fd
 * @param addr
 * @param socklen
 * @param arg
 */

static void listen_cb(struct evconnlistener * evconnlistener, evutil_socket_t fd, struct sockaddr * addr, int socklen, void * arg);

static void write_cb(struct bufferevent* be, void* arg){
    zlog_info(log_get_zlog_c(), "write_cb");
}
static void read_cb(struct bufferevent* be, void* arg){
    zlog_info(log_get_zlog_c(), "read_cb");
    char buf[1024] = {0};
    //读取数据
    int len = bufferevent_read(be, buf, sizeof(buf) - 1);
    if(len <= 0){
        zlog_info(log_get_zlog_c(), "read size is zero");
        return;
    }
    //zlog_info(log_get_zlog_c(), "\n%s", buf);
    //发送数据
    char data[1024] = {0};
    int l = sprintf(data, "HTTP/1.1 200 OK\r\nContent-Length: %d\r\nContent-Type: text/html\r\n\r\n%s", len, buf);
    bufferevent_write(be, data, l);

}
static void event_cb(struct bufferevent* be, short  what, void* arg){
    zlog_info(log_get_zlog_c(), "event_cb");
    //连接断开
    if(what & BEV_EVENT_EOF){
        zlog_info(log_get_zlog_c(), "BEV_EVENT_EOF");
        bufferevent_free(be); //清理
    }
    //错误
    if(what & BEV_EVENT_ERROR) {
        zlog_info(log_get_zlog_c(), "BEV_EVENT_ERROR");
        bufferevent_free(be); //清理
    }

    //读取超时,将不能再读取数据
    if(what & BEV_EVENT_TIMEOUT && what & BEV_EVENT_READING) {
        zlog_info(log_get_zlog_c(), "bufferevent read time out");
        bufferevent_free(be); //清理
        //bufferevent_enable(be, EV_READ); //重新设置可读
    }
}
static void listen_cb(struct evconnlistener * evconnlistener, evutil_socket_t fd, struct sockaddr * addr, int socklen, void * arg){
    struct sockaddr_in* sin =(struct sockaddr_in*) addr;
    //获取客户端的端口和地址
    char client_ip_buf[16] = {0};
    //inet_ntop(AF_INET, &client_addr.sin_addr.s_addr, client_ip_buf, sizeof(client_ip_buf) - 1);
    evutil_inet_ntop(AF_INET, &sin->sin_addr, client_ip_buf, sizeof(client_ip_buf) - 1);
    zlog_info(log_get_zlog_c(), "client ip = %s, port = %d", client_ip_buf, ntohs(sin->sin_port));
    struct event_base * base = (struct event_base*)arg;
    //创建bufferevent上下文
    //BEV_OPT_CLOSE_ON_FREE:清理bufferevent时关闭socket文件描述符
    struct bufferevent* event = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE);
    //添加监听事件
    bufferevent_enable(event, EV_READ|EV_WRITE);
    //设置水位（读）
    bufferevent_setwatermark(event, EV_READ,
                             8, //低水位（默认0 无限制），至少收到10个字节才触发回调
                             0); //高水位(默认0，无限制)，设置后，收到的数据量超过该值，会触发多次回调
    //超时设置
    struct timeval t1 = {3, 0};
    bufferevent_set_timeouts(event, &t1, 0);
    //设置回调函数
    bufferevent_setcb(event, read_cb, write_cb, event_cb, base);
}

void demo_05(){

#ifndef _WIN32
    init();
    zlog_info(log_get_zlog_c(), "buffer event...");
    struct event_base* base = event_base_new();
    if(!base){
        clean();
        perror("event_base_new");
        zlog_error(log_get_zlog_c(), "event_base_new fail");
        return;
    }

    //创建网络服务器
    struct sockaddr_in sin;
    bzero(&sin, sizeof (sin));
    sin.sin_family = AF_INET;
    sin.sin_port = htons(5001);
    //监听端口
    struct evconnlistener * listener = evconnlistener_new_bind(base,
                                                               listen_cb,                                       //回调函数
                                                               base,                                            //自定义数据
                                                               LEV_OPT_REUSEABLE | LEV_OPT_CLOSE_ON_FREE, //地址重用，listen关闭socket
                                                               8,                                      //连接缓冲队列大小
                                                               (struct sockaddr*)&sin,                          //端口
                                                               sizeof(sin));


    //进入事件主循环
    event_base_dispatch(base);
    //释放
    evconnlistener_free(listener);
    event_base_free(base);
    clean();
#endif
}
